package com.kinghood.authoritycenter.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kinghood.authoritycenter.common.model.dao.authority.AuthorityRoleDO;
import com.kinghood.authoritycenter.common.model.dao.authority.AuthorityRoleMenuRelateDO;
import com.kinghood.authoritycenter.common.model.dao.authority.AuthorityUserRoleRelateDO;
import com.kinghood.authoritycenter.common.model.dto.auth.UserDTO;
import com.kinghood.authoritycenter.common.model.dto.authority.AddRoleReqDTO;
import com.kinghood.authoritycenter.common.model.dto.authority.RoleQueryPageReqDTO;
import com.kinghood.authoritycenter.common.model.dto.authority.UpdateRoleReqDTO;
import com.kinghood.authoritycenter.common.model.serviceimpl.AuthorityRoleMenuRelateServiceImpl;
import com.kinghood.authoritycenter.common.model.vo.authority.GetRoleVO;
import com.kinghood.authoritycenter.common.util.UserUtil;
import com.kinghood.authoritycenter.dao.authority.AuthorityRoleMapper;
import com.kinghood.authoritycenter.dao.authority.AuthorityUserRoleRelateMapper;
import com.kinghood.authoritycenter.service.IAuthorityRoleService;
import com.kinghood.infrastructure.model.KingHoodExceptionUtil;
import com.kinghood.infrastructure.model.constant.CommonConstants;
import com.kinghood.infrastructure.util.base.IdGenUtil;
import com.kinghood.sharding.model.KingHoodPageUtil;
import com.kinghood.sharding.model.KingPageResult;
import com.kinghood.sharding.model.PageResponseVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author KingHood
 * @since 2023-12-18
 */
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
@Slf4j
@Service
public class AuthorityRoleServiceImpl extends ServiceImpl<AuthorityRoleMapper, AuthorityRoleDO> implements IAuthorityRoleService {

    private final AuthorityUserRoleRelateMapper userRoleRelateMapper;
    private final AuthorityRoleMenuRelateServiceImpl roleMenuRelateService;

    @Override
    public PageResponseVO<AuthorityRoleDO> queryPage(RoleQueryPageReqDTO in) {
        Page<AuthorityRoleDO> page = this.baseMapper.queryPage(KingHoodPageUtil.getPage(in, in), in);
        return KingPageResult.getResult(page);
    }

    @Override
    public AuthorityRoleDO addRole(AddRoleReqDTO in) {

        // 角色名字和code重复
        Long count = new LambdaQueryChainWrapper<>(this.getBaseMapper())
                .eq(AuthorityRoleDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .and(x->x.eq(AuthorityRoleDO::getCode, in.getCode())
                        .or().eq(AuthorityRoleDO::getName, in.getName()))
                .count();
        KingHoodExceptionUtil.trueThrows(count > 0, "角色的code或名字已存在");

        AuthorityRoleDO one = new AuthorityRoleDO();
        BeanUtils.copyProperties(in, one);
        UserDTO user = UserUtil.getUser();
        Date now = new Date();
        one.setCreateTime(now);
        one.setUpdateTime(now);
        one.setCreateUserId(UserUtil.getUserId());
        one.setUpdateUserId(UserUtil.getUserId());
        one.setId(IdGenUtil.get().nextId());
        this.save(one);

        if (CollectionUtils.isNotEmpty(in.getMenuIdList())) {
            saveRoleMenuRelate(one.getId(), UserUtil.getUserId(), now, in.getMenuIdList());
        }

        log.info("新增角色：{}，操作人：{}", in, user);

        return one;
    }

    @Override
    public GetRoleVO getRole(Long id) {

        return this.getBaseMapper().getRole(id);
    }

    @Override
    public AuthorityRoleDO updateRole(UpdateRoleReqDTO in) {
        AuthorityRoleDO one = this.getById(in.getId());
        KingHoodExceptionUtil.isNull(one, "角色不存在");

        if(!Objects.equals(in.getCode(),one.getCode()) || Objects.equals(in.getName(),one.getName())){
            // 角色名字和code重复
            Wrappers.<AuthorityRoleDO>lambdaQuery().eq(AuthorityRoleDO::getId, in.getId());
            Long count = new LambdaQueryChainWrapper<>(this.getBaseMapper())
                    .eq(AuthorityRoleDO::getIsDelete, CommonConstants.IS_DELETE_N)
                    .notIn(AuthorityRoleDO::getId, in.getId())
                    .and(x -> x.eq(AuthorityRoleDO::getCode, in.getCode())
                            .or().eq(AuthorityRoleDO::getName, in.getName()))
                    .count();
            KingHoodExceptionUtil.trueThrows(count > 0, "角色的code或名字已存在");
        }

        BeanUtils.copyProperties(in, one);
        UserDTO user = UserUtil.getUser();
        Date now = new Date();
        one.setUpdateTime(now);
        one.setUpdateUserId(UserUtil.getUserId());
        this.updateById(one);

        // 删除原来的绑定
        new LambdaUpdateChainWrapper<>(roleMenuRelateService.getBaseMapper())
                .eq(AuthorityRoleMenuRelateDO::getRoleId, in.getId())
                .remove();

        if (CollectionUtils.isNotEmpty(in.getMenuIdList())) {
            saveRoleMenuRelate(one.getId(), UserUtil.getUserId(), now, in.getMenuIdList());
        }

        log.info("修改角色：{}，操作人：{}", in, user);

        return one;
    }

    private void saveRoleMenuRelate(Long roleId, Long userId, Date now, List<Long> menuIdList) {
        List<AuthorityRoleMenuRelateDO> list = menuIdList.stream().map(x -> {
            AuthorityRoleMenuRelateDO relateDO = new AuthorityRoleMenuRelateDO();
            relateDO.setId(IdGenUtil.get().nextId());
            relateDO.setRoleId(roleId);
            relateDO.setMenuId(x);
            relateDO.setCreateTime(now);
            relateDO.setUpdateTime(now);
            relateDO.setCreateUserId(userId);
            relateDO.setUpdateUserId(userId);
            return relateDO;
        }).collect(Collectors.toList());
        roleMenuRelateService.saveBatch(list);
    }

    @Override
    public Boolean deleteRoleBatch(List<Long> idList) {

        KingHoodExceptionUtil.isEmpty(idList, "请选择要删除的角色");

        long enableCount = new LambdaQueryChainWrapper<>(this.getBaseMapper())
                .in(AuthorityRoleDO::getId, idList)
                .eq(AuthorityRoleDO::getStatus, CommonConstants.ENABLE)
                .eq(AuthorityRoleDO::getIsDelete, CommonConstants.IS_DELETE_N).count();
        KingHoodExceptionUtil.trueThrows(enableCount > 0, "启用状态不允许删除");

        long count = new LambdaQueryChainWrapper<>(userRoleRelateMapper)
                .in(AuthorityUserRoleRelateDO::getRoleId, idList)
                .eq(AuthorityUserRoleRelateDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .count();

        KingHoodExceptionUtil.trueThrows(count > 0, "角色下有用户，无法删除");

        UserDTO user = UserUtil.getUser();
        boolean update = new LambdaUpdateChainWrapper<>(this.getBaseMapper())
                .in(AuthorityRoleDO::getId, idList)
                .set(AuthorityRoleDO::getIsDelete, CommonConstants.IS_DELETE_Y)
                .set(AuthorityRoleDO::getUpdateUserId, UserUtil.getUserId())
                .set(AuthorityRoleDO::getUpdateTime, new Date())
                .update();

        log.info("删除角色：{}，结果：{}，操作人：{}", idList, update, user);
        return update;
    }

    /**
     * 角色启用禁用
     */
    @Override
    public Boolean updateStatus(Long id, Integer status) {

        //关闭的时候需要判断是否有绑定用户
        if (Objects.equals(status, CommonConstants.DISABLE)) {

            Long count = new LambdaQueryChainWrapper<>(userRoleRelateMapper)
                    .eq(AuthorityUserRoleRelateDO::getRoleId, id)
                    .eq(AuthorityUserRoleRelateDO::getIsDelete, CommonConstants.IS_DELETE_N)
                    .count();

            KingHoodExceptionUtil.trueThrows(count > 0, "该角色下有用户，无法关闭");
        }

        UserDTO user = UserUtil.getUser();
        boolean update = new LambdaUpdateChainWrapper<>(this.getBaseMapper())
                .in(AuthorityRoleDO::getId, id)
                .set(AuthorityRoleDO::getStatus, status)
                .set(AuthorityRoleDO::getUpdateUserId, UserUtil.getUserId())
                .set(AuthorityRoleDO::getUpdateTime, new Date())
                .update();

        log.info("修改角色：{}的status状态为：{}，结果：{}，操作人：{}", id, status, update, user);
        return update;
    }

    /**
     * 用于下拉列
     */
    @Override
    public List<AuthorityRoleDO> getRoleList() {

        return new LambdaQueryChainWrapper<>(this.getBaseMapper())
                .eq(AuthorityRoleDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .eq(AuthorityRoleDO::getStatus, CommonConstants.ENABLE)
                .orderByAsc(AuthorityRoleDO::getCreateTime)
                .list();
    }
}
